import Koa, { Middleware } from 'koa';
import bodyParser from 'koa-bodyparser';
import path from 'path';
import chalk from 'chalk';
import KoaViews from 'koa-views';
import KoaStatic from 'koa-static';
import { KoaCORS } from './middlewares/cors.middleware';
import HttpProxy from './middlewares/httpProxyWidthMode.middleware';
import { RouterRegister } from './routes/router.register';

import { loadRoutes } from './routes/router.load';
import { proxyConfig } from './proxy.config';

const STATIC_PATH = './static';
const VIEW_PATH = './views';

process.on('uncaughtException', (error) => {
    console.error(chalk.red('global uncaughtException->'), error)
});

process.on('unhandledRejection', (error) => {
    console.log(chalk.red('global unhandledRejection->'), error);
})

interface ListenOptions {
    port?: number;
    host?: string;
    backlog?: number;
    path?: string;
    exclusive?: boolean;
    readableAll?: boolean;
    writableAll?: boolean;
    /**
     * @default false
     */
    ipv6Only?: boolean;
}

class KoaServe {

    private readonly app = new Koa();
    options: ListenOptions = { port: 8077 };

    constructor(options?: ListenOptions) {
        if (options) {
            this.options = Object.assign(this.options, options);
        }
    }

    getApp() {
        return this.app;
    }

    use(middlewares: Koa.Middleware[]) {
        if (!Array.isArray(middlewares)) {
            this.app.use(middlewares);
            return this;
        }
        middlewares.forEach(middlewaresItem => {
            this.app.use(middlewaresItem);
        })
        return this;
    }

    listen(actionCallback = () => { }) {
        this.app.listen(this.options, actionCallback);
        return this;
    }

    onerror(actionCallback = (err: Error, ctx: Koa.Context) => { }) {
        this.app.on('error', actionCallback);
        return this;
    }

    onupdate(actionCallback = (ctx: Koa.Context) => { }) {
        this.app.on('upgrade', actionCallback);
        return this;
    }
}

const middlewares: Koa.Middleware[] = [
    KoaStatic(path.join(__dirname, STATIC_PATH)),
    KoaViews(path.join(__dirname, VIEW_PATH), {
        extension: 'ejs'
    }),
    KoaCORS(),
    bodyParser({
        enableTypes: ['json', 'form', 'text']
    }),
    async (ctx: Koa.Context, next) => {
        await next();
    },
    HttpProxy(
        proxyConfig
    ),
    // two routerRegister methods, you can use one of them
    // one router register
    ...new RouterRegister().routerRegister(),
    // two router register
    ...loadRoutes(),
    async (ctx: Koa.Context, next: Koa.Next) => {
        console.log('not found-start->');
        await next()
        console.log('not found-end->');
    }

]

const koaServer = new KoaServe();
koaServer.use(middlewares).listen(() => {
    console.log(chalk.green('-------------start-------------'));
    console.log('----serve options----', koaServer.options);
    console.log('----proxy----', proxyConfig);
}).onerror((err: Error, ctx: Koa.Context) => {
    console.error(chalk.red('ERROR->'), `[${ctx.method}]${ctx.url} ${err.message}`);
}).onupdate((ctx: Koa.Context) => {
    console.log('upgrade-------------', ctx);
});